#include "Inf_OV2640.h"

// support IDF 5.x
#ifndef portTICK_RATE_MS
#define portTICK_RATE_MS portTICK_PERIOD_MS
#endif

#define CAM_PIN_PWDN 40
#define CAM_PIN_RESET 42 // software reset will be performed
#define CAM_PIN_VSYNC 41
#define CAM_PIN_HREF 39
#define CAM_PIN_PCLK 34
#define CAM_PIN_XCLK 37
#define CAM_PIN_SIOD 0
#define CAM_PIN_SIOC 1
#define CAM_PIN_D0 9
#define CAM_PIN_D1 11
#define CAM_PIN_D2 12
#define CAM_PIN_D3 10
#define CAM_PIN_D4 33
#define CAM_PIN_D5 35
#define CAM_PIN_D6 36
#define CAM_PIN_D7 38

static const char *TAG = "example:take_picture";

// 帧缓冲区，用于存储图像数据
camera_fb_t  *pic = NULL;

static camera_config_t camera_config = {
    .pin_pwdn = CAM_PIN_PWDN,
    .pin_reset = CAM_PIN_RESET,
    .pin_xclk = CAM_PIN_XCLK,
    .pin_sccb_sda = CAM_PIN_SIOD,
    .pin_sccb_scl = CAM_PIN_SIOC,

    .pin_d7 = CAM_PIN_D7,
    .pin_d6 = CAM_PIN_D6,
    .pin_d5 = CAM_PIN_D5,
    .pin_d4 = CAM_PIN_D4,
    .pin_d3 = CAM_PIN_D3,
    .pin_d2 = CAM_PIN_D2,
    .pin_d1 = CAM_PIN_D1,
    .pin_d0 = CAM_PIN_D0,
    .pin_vsync = CAM_PIN_VSYNC,
    .pin_href = CAM_PIN_HREF,
    .pin_pclk = CAM_PIN_PCLK,
    // XCLK 时钟频率，20MHz 或 10MHz 可让 OV2640 实现双倍帧率（实验性）
    .xclk_freq_hz = 20000000,
    // 用于生成 XCLK 信号的 LEDC 定时器
    .ledc_timer = LEDC_TIMER_0,
    // 用于生成 XCLK 信号的 LEDC 通道
    .ledc_channel = LEDC_CHANNEL_0,
    // 像素格式，可选择 YUV422、GRAYSCALE、RGB565、JPEG 等，此处选择 RGB565
    .pixel_format = PIXFORMAT_JPEG,
    .frame_size = FRAMESIZE_QVGA, // QQVGA-UXGA, For ESP32, do not use sizes above QVGA when not JPEG. The performance of the ESP32-S series has
                                  // improved a lot, but JPEG mode always gives better frame rates.

    // JPEG 图像质量，范围 0 - 63，对于 OV 系列摄像头传感器，数值越小质量越高
    .jpeg_quality = 12,
    // 帧缓冲区数量，当使用 JPEG 模式时，如果 fb_count 大于 1，驱动将工作在连续模式
    .fb_count = 1,
    // 帧缓冲区存储位置，此处设置为 PSRAM
    .fb_location = CAMERA_FB_IN_PSRAM,
    // 帧抓取模式，当缓冲区为空时进行抓取
    .grab_mode = CAMERA_GRAB_WHEN_EMPTY,
};

/**
 * @brief 初始化
 *
 */
void Inf_OV2640_Init(void) {
  // initialize the camera
  esp_err_t err = esp_camera_init(&camera_config);
  if (err != ESP_OK) {
    ESP_LOGE(TAG, "初始化 失败");
  }
}

// 获取照片
void Inf_OV2640_GetPicture(uint8_t **data, size_t *len){
     // 拍照
     pic = esp_camera_fb_get();

     // 接收数据
     if (pic->buf != NULL && pic->format == PIXFORMAT_JPEG)
     {
         *data = pic->buf;
         *len = pic->len;
     }
}

/**
 * @description: 释放图片使用的内存
 * @return {*}
 */
void Inf_OV2640_FreePicture(void)
{
    if (pic != NULL)
    {
        esp_camera_fb_return(pic);
    }
}
